#ifndef _SFS_DATA_SVR_H_
#define _SFS_DATA_SVR_H_

#include <string>
#include <set>

#include <log4cxx/logger.h>
#include <json/json.h>

#include "ServerFrameWork.h"
#include "CnfSvrClient.h"
#include "DataSvrClient.h"
#include "MetadataSvrClient.h"

using std::string;
using std::set;

using namespace log4cxx;

struct REPLICATE_TASK {
	int32_t dir_id;
	int64_t file_id;
	int32_t src_ds_id;
	int64_t src_file_size;
	vector<uint32_t> src_crcs;
	bool operator < (const REPLICATE_TASK & t) const {
		return (this->dir_id == t.dir_id ? (this->file_id < t.file_id) : (this->dir_id < t.dir_id));
	} 
};

class DataSvr {

	public:
		int init(const char * log_conf_file, int32_t my_ds_id, const char * cs_ip, unsigned short cs_port, \
				int cs_conn_pool_size, int cs_socket_conn_timeout, int cs_socket_send_timeout, \
				int cs_socket_recv_timeout, int cs_socket_max_response_size);
		int start();
	protected:
		static int handle_socket_input_func(int fd, void * arg);
		
		static void * replicate_thread_routine(void * arg);

                int dispatch_request(int cmd_id, json_object * j, string & response, string & extra_response, const int fd, \
					bool & is_network_error);

                int handle_create_file(json_object * j, string & response, string & extra_response, const int fd, \
					bool & is_network_error);

                int handle_delete_file(json_object * j, string & response, string & extra_response, const int fd, \
					bool & is_network_error);

		int handle_read_file(json_object * j , string & response, string & extra_response, const int fd, \
					bool & is_network_error);
		
		int handle_write_file(json_object * j, string & response, string & extra_response, const int fd, \
					bool & is_network_error);

		int handle_get_file_control_info(json_object * j, string & response, string & extra_response, const int fd, \
					bool & is_network_error);

		int handle_replicate(json_object * j, string & response, string & extra_response, const int fd, \
					bool & is_network_error);

		int handle_truncate(json_object * j, string & response, string & extra_response, const int fd, \
					bool & is_network_error);


		int put_replicate_task_to_queue(REPLICATE_TASK task);

		int get_replicate_task_from_queue(REPLICATE_TASK & task);

		int replicate(const int32_t dir_id, const int64_t file_id, const int32_t src_ds_id, const int64_t src_file_size, \
				const vector<uint32_t> src_crcs);

		int rebuild_crc(const int dir_id, const int64_t file_id, const int64_t write_begin_pos, const int write_len);

		int create_new_file(int32_t dir_id, int64_t file_id);
		
		int write_file(int32_t dir_id, int64_t file_id, int64_t begin_pos, const char * buf, int64_t len, int32_t mode);
		
		int total_rebuild_crc(const int dir_id, const int64_t file_id);
		int notify_mds_file_info(int32_t dir_id, int64_t file_id, int delete_flag, int notify_reason);
	private:
		static LoggerPtr _logger;
		string _listen_ip;
		unsigned short _listen_port;
		int _thread_num;
		string _log_conf_file;
		int _socket_idle_timeout;
		int _socket_send_timeout;
		int _socket_recv_timeout;
		int _max_request_size;
		string _root_data_path;
		int32_t _my_ds_id;
		int32_t _my_mds_id;
		ServerFrameWork _sfw;
		CnfSvrClient _csc;
		DataSvrClientGroup _dscg;
		MetadataSvrClientGroup _mdscg;
		set<REPLICATE_TASK> _replicate_tasks;
		pthread_mutex_t _replicate_tasks_mutex;
		pthread_cond_t _replicate_tasks_cond;
		pthread_t _replicate_thread;
};

#endif
